################################################################################
#* Licensed Materials - Property of IBM  
#*  
#* OCO Source Materials  
#*  
#* (C) Copyright IBM Corp. 2014 All Rights Reserved  
#*  
#* The source code for this program is not published or other-  
#* wise divested of its trade secrets, irrespective of what has  
#* been deposited with the U.S. Copyright Office.  
################################################################################

################################################################################
# Author:yushaoyang@cn.ibm.com
# Createdate:Sun May 10 23:18:31 2015
# Lastupd:Sun May 10 23:18:31 2015

# Description
# Updatelog:
# 1. "Create the file"
################################################################################
module Restful
  module RouterDSL
    def self.included target
      #Define instance methods
      target.send(:define_method,"url"){
        _reqctx[:url]||=""
      }


      target.send(:define_method,"qparams"){
        _reqctx[:qparams]||={}
      }

      target.send(:define_method,"body"){
        _reqctx[:body]||=""
      }

      target.send(:define_method,"header"){
        _reqctx[:header]||=""
      }

      target.send(:define_method,"xparams"){
        _reqctx[:xparams]||={}
      }

      target.send(:define_method,"_reqctx"){
        @_reqctx||={}
        @_reqctx
      }

      target.send(:define_method,"router_missing"){|*params|
        _method,_url,_qparams,_body,_header=params
        result=[]
        result<< "No Router found"
        result<< "Method:#{_method}"
        result<< "url:#{_url}"
        result=result.join("\n")
        log.debug result
        result
      }

      target.send(:define_method,"error_handler"){|e|
      }

      target.send(:define_method,"doReq"){|*_params|
        # params=[method,url,qparams,body,header]
        begin
        _method,_reqctx[:url],_reqctx[:qparams],_reqctx[:body],_reqctx[:header],_reqctx[:xparams]=_params
        code=200
        result=nil
        _actions=self.class._actions
        node=_actions[_method]
        path=url.split("/")
        _selected=nil
        path.each{|subpath|
          _selected=node.select{|k,v| 
            matchdata=/#{k.to_s}/.match subpath;
            xparams[:splat]||=[]
            xparams[:splat]+=matchdata[1..-1] if matchdata and matchdata.length>1
            matchdata
          }
          if _selected.empty?
            node=nil
            break
          else
            node=_selected.first.last
          end
        }

        if node and node[:action]
          log.debug _selected
          _block=node[:action]
          result=self.instance_exec &_block 
        else
          result=router_missing _method,url,qparams,body,header
          code=400
        end
        rescue => e
          code=400
          result=e.to_s
          log.error e
          error_handler e
        end

        return result,code
      }


      target.send(:define_method,"doGet"){|*params|
        self.doReq :GET,*params
      }

      target.send(:define_method,"doPost"){|*params|
        self.doReq :POST,*params
      }

      target.send(:define_method,"doPut"){|*params|
        self.doReq :PUT,*params
      }

      target.send(:define_method,"doDelete"){|*params|
        self.doReq :DELETE,*params
      }


      # Define class methods
      def target.GET path,&action
        _method :GET,path,&action
      end

      def target.POST path,&action
        _method :POST,path,&action
      end
      def target.DELETE path,&action
        _method :DELETE,path,&action
      end
      def target.PUT path,&action
        _method :PUT,path,&action
      end
      def target.PATCH path,&action
        _method :PATCH,path,&action
      end

      
      def target._method method,path,&action
        require 'uri'
#        path=URI(path).path
        path=path.split("/")
        _actions[method]||={}
        node=_actions[method]
        path.each{|subpath|
          subpath="^#{subpath}\\z" 
          subpath.gsub!('*','(\w*)')
          subpath.gsub!('.','\.')
          subpath.gsub!('\d','(\d*)')

          node[subpath]||={}
          node=node[subpath]
        }
        node[:action]=action
      end
      
      def target._actions
        @_actions||={}
      end

    end
  end
end
